﻿using System;
using dnAnalytics.LinearAlgebra;
using NUnit.Framework;

namespace dnAnalytics.Tests.LinearAlgebra
{
    [TestFixture]
    public class HouseholderTransformationTests
    {
        [Test]
        public void MatrixTest()
        {
            DenseVector x = new DenseVector(new double[] {3, 1, 5, 1});
            HouseholderTransformation house = new HouseholderTransformation(x);

            Vector transform = house.ReflectionMatrix()*x;
            Assert.AreEqual(6, System.Math.Abs(transform[0]), 1e-15);
            Assert.AreEqual(0, transform[1], 1e-15);
            Assert.AreEqual(0, transform[2], 1e-15);
            Assert.AreEqual(0, transform[3], 1e-15);
        }

        [Test]
        public void NullConstructor()
        {
            Assert.Throws<ArgumentNullException>(() => new HouseholderTransformation(null));
        }

        [Test]
        public void TransformationTest()
        {
            DenseVector x = new DenseVector(new double[] {3, 1, 5, 1});
            HouseholderTransformation house = new HouseholderTransformation(x);

            Vector transform = house.Transformation();
            Assert.AreEqual(6, System.Math.Abs(transform[0]), 1e-15);
            Assert.AreEqual(0, transform[1], 1e-15);
            Assert.AreEqual(0, transform[2], 1e-15);
            Assert.AreEqual(0, transform[3], 1e-15);

            x = new DenseVector(new double[] {-3, 1, 5, 1});
            house = new HouseholderTransformation(x);

            transform = house.Transformation();
            Assert.AreEqual(6, System.Math.Abs(transform[0]), 1e-15);
            Assert.AreEqual(0, transform[1], 1e-15);
            Assert.AreEqual(0, transform[2], 1e-15);
            Assert.AreEqual(0, transform[3], 1e-15);
        }

        [Test]
        public void VectorTest()
        {
            DenseVector x = new DenseVector(new double[] {3, 1, 5, 1});
            HouseholderTransformation house = new HouseholderTransformation(x);

            Vector vector = house.ReflectionVector();
            double constant = 2.0/vector.DotProduct(vector);
            Matrix I = vector.CreateMatrix(vector.Count, vector.Count);
            for (int i = 0; i < vector.Count; i++)
            {
                I[i, i] = 1.0;
            }
            Matrix vt = vector.Multiply(vector);
            Matrix p = I - (constant*vt);

            Vector transform = p*x;
            Assert.AreEqual(6, System.Math.Abs(transform[0]), 1e-15);
            Assert.AreEqual(0, transform[1], 1e-15);
            Assert.AreEqual(0, transform[2], 1e-15);
            Assert.AreEqual(0, transform[3], 1e-15);
        }
    }
}